package hyl.base.net.nio;

import java.nio.ByteBuffer;

import hyl.base.net.IData1;
import hyl.core.MyFun;

/**
 * 最底层的数据包基于NIO 的TCP
 * 
 * @author 37798955@qq.com
 *
 */
public class NIOData1 implements IData1<ByteBuffer>, Cloneable {

	// 0:未知(可以丢弃); 1:消息; 2:命令

	byte i类型 = B类型_未知;
	byte[] data;

	public NIOData1 clone() {
		try {
			NIOData1 ob = (NIOData1) super.clone();
			ob.reset();
			return ob;
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
			return null;
		}
	}

	public ByteBuffer getSendBytes() {
		int len = 5 + data.length;
		ByteBuffer bb = ByteBuffer.allocate(len);
		bb.put(i类型);
		bb.putInt(data.length);
		bb.put(data);
		bb.flip();
		// 从position位置开始相对读，读length个byte，并写入dst下标从offset到offset+length的区域
		// byte[] bs=new byte[len];
		// bb.get(bs,0,len);
		// 这个地方要特别注意,缺少就无法发送了 因为 pos 没有回到
		return bb;
	}

	public byte getB类型() {
		return i类型;
	}

	public void setI类型(byte i类型) {
		this.i类型 = i类型;
	}

	public byte[] getData() {
		return data;
	}

	public void setData(byte[] 数据) {
		if (数据 == null)
			return;
		this.data = 数据;
	}

	public int _step = 0;
	int _datalen = 0;
	byte[] 已经读取字节 = null;

	void reset() {
		i类型 = B类型_未知;
		_datalen = 0;
		_step = 0;
		data = null;
	}

	/**
	 * 
	 * @param 数据 这里的数据必须是 flip 好了的
	 * @return
	 */
	public boolean addData(ByteBuffer 数据) {
		if (数据 == null || !数据.hasRemaining())
			return false;
		// 数据.flip();
		if (_step == 0) {
			// 省略remaining 长度判断 因为 前面已经判断
			i类型 = 数据.get();
			if (i类型 > IData1.B类型_未知)
				_step = 1;
			else {// 无效数据 抛弃
				reset();
				return false;
			}
		}

		if (_step == 1) {
			if (数据.remaining() >= 4) {
				_datalen = 数据.getInt();
				if (_datalen > 0)
					_step = 3;
				else {
					reset();
					return false;
				}
			} else {
				_step = 2;
				已经读取字节 = new byte[数据.remaining()];
				数据.get(已经读取字节);
				return false;
			}
		}
		if (_step == 2) {
			if (do补充剩余字节(4, 数据)) {
				_datalen = MyFun.byteArray2Int(已经读取字节);
				_step = 3;
				已经读取字节 = null;
			} else
				return false;
		}

		if (_step == 3) {
			if (数据.remaining() >= _datalen) {
				data = new byte[_datalen];
				// System.out.println("++"+数据.remaining());
				数据.get(data);
				// 数据.array();
				_step = 5;
			} else {
				_step = 4;
				已经读取字节 = new byte[数据.remaining()];
				数据.get(已经读取字节);
				return false;
			}
		}
		if (_step == 4) {
			if (do补充剩余字节(_datalen, 数据)) {
				data = 已经读取字节;
				_step = 5;
				已经读取字节 = null;
			} else
				return false;

		}

		return true;

	}

	/**
	 * 从数据中取 k字节 补充到
	 * 
	 * @param 期望长度
	 * @param 已经读取字节
	 * @param 数据
	 * @return true 补充结束, false 未补充结束
	 */
	boolean do补充剩余字节(int 期望长度, ByteBuffer 数据) {
		int k = 期望长度 - 已经读取字节.length;
		// 如果 数据不足或者不需要补充字节 那么退出
		if (k == 0 || 数据.remaining() == 0)
			return false;
		// 如果数据足够 读取到
		if (数据.remaining() >= k) {
			byte[] 新增字节 = new byte[k];
			数据.get(新增字节);
			已经读取字节 = MyFun.concat(已经读取字节, 新增字节);
			return true;
		} else {
			// 先补充部分字节
			byte[] 新增字节 = new byte[数据.remaining()];
			数据.get(新增字节);
			已经读取字节 = MyFun.concat(已经读取字节, 新增字节);
			return false;
		}

	}
}
